package cn.cycleif.app.service;

import cn.cycleif.app.domain.dto.UserChangeMailDTO;
import cn.cycleif.app.domain.dto.UserChangePwdDTO;
import cn.cycleif.app.domain.dto.UserProfileDTO;
import cn.cycleif.app.domain.dto.UserRegisterDTO;
import cn.cycleif.app.mapper.RoleMapper;
import cn.cycleif.app.mapper.UserMapper;
import cn.cycleif.app.mapper.UserRoleMapper;
import cn.cycleif.entity.Role;
import cn.cycleif.entity.User;
import cn.cycleif.entity.UserRole;
import cn.cycleif.enums.ResultCodeEnum;
import cn.cycleif.enums.UserStatusEnum;
import cn.cycleif.util.EncryptUtil;
import cn.cycleif.util.R;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
 * @Date: 25/1/21-16:45
 * @Desc:
 */
@Service
@RequiredArgsConstructor
public class UserService extends ServiceImpl<UserMapper, User> {

  private final UserMapper     userMapper;
  private final RoleMapper     roleMapper;
  private final UserRoleMapper userRoleMapper;

  public R<String> insert(UserRegisterDTO userRegisterDTO) {
    if (StringUtils.isEmpty(userRegisterDTO.getUsername())
        && StringUtils.isEmpty(userRegisterDTO.getEmail()))
      return R.error(ResultCodeEnum.ERROR_REQUEST_FORMAT);
    // 校验用户名与邮箱的唯一性
    User user1 = userMapper.selectOne(
        new LambdaQueryWrapper<User>().eq(User::getUsername, userRegisterDTO.getUsername())
    );
    if (user1 != null)
      return R.error("用户已存在");
    User user2 = userMapper.selectOne(
        new LambdaQueryWrapper<User>().eq(User::getMail, userRegisterDTO.getEmail())
    );
    if (user2 != null)
      return R.error("邮箱已存在");
    if (StringUtils.isEmpty(userRegisterDTO.getUsername())) {
      String randomUserName = "user#" + RandomUtil.randomNumbers(6);
      userRegisterDTO.setUsername(randomUserName);
    }
    // 校验完成
    User user = BeanUtil.copyProperties(userRegisterDTO, User.class);
    user.setUsername(userRegisterDTO.getUsername());
    user.setDisplayName(userRegisterDTO.getUsername());
    user.setMail(userRegisterDTO.getEmail());
    user.setPassword(EncryptUtil.encrypt(userRegisterDTO.getPasswd()));
    user.setStatus(UserStatusEnum.ACTIVE);  // 默认激活
    userMapper.insert(user);
    // 初始用户没有角色
    return R.success();
  }

  public R<String> changePwd(UserChangePwdDTO user) {
    // 查询用户
    User dbUser = userMapper.selectById(user.getId());
    if (ObjectUtil.isNull(dbUser))
      return R.error(ResultCodeEnum.ERROR_USER_NOT_EXIST);

    // 验证旧密码
    if (!EncryptUtil.validate(dbUser.getPassword(), user.getRawPasswd()))
      return R.error(ResultCodeEnum.ERROR_PASSWORD_WRONG);

    // 检查二次确定
    if (!user.getNewPasswd().equals(user.getNewPasswdConfirm()))
      return R.error(ResultCodeEnum.ERROR_PASSWORD_NOT_MATCH);

    // 更新密码
    dbUser.setPassword(EncryptUtil.encrypt(user.getNewPasswd()));
    userMapper.updateById(dbUser);
    return R.success();
  }

  public R<Object> getUserInfoById(Integer id) {
    User user = userMapper.selectById(id);
    if (ObjectUtil.isNull(user)) return R.error(ResultCodeEnum.ERROR_USER_NOT_EXIST);
    user.setPassword("*");
    user.setMail(null);
    HashMap<String, Object> map = getUserDetail(user);
    return R.success(map);
  }

  public R<Object> getCurrentUserInfo() {
    Long userId = StpUtil.getLoginIdAsLong();
    User user   = baseMapper.selectById(userId); // 或使用 token 查询
    user.setPassword("*");
    HashMap<String, Object> map = getUserDetail(user);
    return R.success(map);
  }

  public R<String> updateUser(UserProfileDTO userProfileDTO) {
    int userId = StpUtil.getLoginIdAsInt();
    // 检查
    User user1 = userMapper.selectById(userId);
    if (ObjectUtil.isNull(user1)) return R.error(ResultCodeEnum.ERROR_USER_NOT_EXIST);
    // 用户名是否重复
    User dbUser = userMapper.selectOne(
        new LambdaQueryWrapper<User>().eq(User::getUsername, userProfileDTO.getUsername())
    );
    if (dbUser != null && dbUser.getId() != userId)
      return R.error("用户名已存在");
    // 更新
    User user = BeanUtil.copyProperties(userProfileDTO, User.class);
    user.setId(user1.getId());
    userMapper.updateById(user);
    return R.success();
  }


  /**
   * 额外获得用户角色信息
   *
   * @param user
   * @return
   */
  @NotNull
  private HashMap<String, Object> getUserDetail(User user) {
    List<String>            roleNames = getRoleNames(user.getId());
    HashMap<String, Object> map       = new HashMap<>();
    map.put("user", user);
    map.put("roles", roleNames);
    return map;
  }

  /**
   * 获取用户精简信息，包括角色信息
   *
   * @param id
   * @return
   */
  public HashMap<String, Object> getUserSimpleInfo(Integer id, Map<String, Supplier<Object>> extraColumn) {
    User user = userMapper.selectById(id);

    HashMap<String, Object> userInfo = new HashMap<>();
    userInfo.put("id", user.getId());
    userInfo.put("displayName", user.getDisplayName());
    userInfo.put("username", user.getUsername());
    userInfo.put("avatar", user.getAvatar());
    userInfo.put("ranks", user.getRanks());
    userInfo.put("status", user.getStatus());
    userInfo.put("roles", getRoleNames(id));

    if (extraColumn != null)
      extraColumn.forEach((k, v) -> userInfo.put(k, v.get()));
    return userInfo;
  }

  @NotNull
  public List<String> getRoleNames(Integer id) {
    List<UserRole> roles = userRoleMapper.selectList(
        new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, id)
    );
    List<String> roleNames = new ArrayList<>();
    for (UserRole userRole : roles) {
      Role role = roleMapper.selectById(userRole.getRoleId());
      roleNames.add(role.getName());
    }
    return roleNames;
  }

  public R<Object> getStaffList() {
    Role role =
        roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getName, "staff"));
    if (role == null) {
      return R.success();
    }
    LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(UserRole::getRoleId, role.getId());
    List<UserRole> userRoles = userRoleMapper.selectList(wrapper);
    // 查询用户列表
    List<HashMap<String, Object>> result = new ArrayList<>();
    for (UserRole userRole : userRoles) {
      HashMap<String, Object> map = getUserSimpleInfo(userRole.getUserId(), null);
      result.add(map);
    }
    return R.success(result);
  }

  public R<Object> getRankList() {
    // 根据用户贡献排序
    Page<User>               page    = new Page<>(1, 20);
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(User::getStatus, UserStatusEnum.ACTIVE.getCode()); // 激活状态
    wrapper.orderByDesc(User::getRanks); // 排序
    List<User>                    userList = userMapper.selectPage(page, wrapper).getRecords();
    List<HashMap<String, Object>> result   = new ArrayList<>();

    for (User user : userList) {
      HashMap<String, Object> map = getUserSimpleInfo(user.getId(), null);
      result.add(map);
    }
    return R.success(result);
  }

  public R<Object> getUserInfoByName(String name) {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(User::getUsername, name);
    User user = userMapper.selectOne(wrapper);
    if (ObjectUtil.isNull(user)) return R.error(ResultCodeEnum.ERROR_USER_NOT_EXIST);
    user.setPassword("*");
    user.setMail(null);
    HashMap<String, Object> map = getUserDetail(user);
    return R.success(map);
  }

  public R<String> changeMail(UserChangeMailDTO user) {
    // 查询用户
    User dbUser = userMapper.selectById(user.getId());
    if (ObjectUtil.isNull(dbUser))
      return R.error(ResultCodeEnum.ERROR_USER_NOT_EXIST);
    // 验证旧密码
    if (!EncryptUtil.validate(dbUser.getPassword(), user.getPasswd()))
      return R.error(ResultCodeEnum.ERROR_PASSWORD_WRONG);
    dbUser.setMail(user.getEmail());
    // 更新
    userMapper.updateById(dbUser);
    return R.success();
  }
}
